#include <stdio.h>

#include <libxml/parser.h>
#include <libxml/tree.h>

#define XML_FILE_NAME "/tmp/demo.xml"

static void xml_save(void)
{
    /* 定义文档和节点指针 */
    xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");
    xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST"\"root\"");

    /* 设置根节点 */
    xmlDocSetRootElement(doc, rootNode);

    /* 在根节点下直接创建子节点 */
    xmlNewTextChild(rootNode, NULL, BAD_CAST"newNode1", BAD_CAST"newNode1 Content");
    xmlNewTextChild(rootNode, NULL, BAD_CAST"newNode2", BAD_CAST"newNode2 Content");
    xmlNewTextChild(rootNode, NULL, BAD_CAST"newNode3", BAD_CAST"newNode3 Content");

    /* 创建一个节点，并设置其内容和属性， 然后加入根节点 */
    xmlNodePtr node = xmlNewNode(NULL, BAD_CAST"newNode4");
    xmlNodePtr content = xmlNewText(BAD_CAST"newNode4 Content");

    xmlAddChild(rootNode, node);
    xmlAddChild(node, content);

    xmlNewProp(node, BAD_CAST"attribute", BAD_CAST"yes");

    /* 创建一个儿子节点和孙子节点 */
    xmlNodePtr son = xmlNewNode(NULL, BAD_CAST"son");
    xmlAddChild(rootNode, son);

    xmlNodePtr grandson = xmlNewNode(NULL, BAD_CAST"grandson");
    xmlAddChild(son, grandson);
    xmlAddChild(grandson, xmlNewText(BAD_CAST"This is a grandson node"));

    /* 存储XML文档 */
    int len = xmlSaveFile(XML_FILE_NAME, doc);
    if (len != -1) {
        printf("write %d bytes into xml document\n", len);
    }

    /* 释放文档内节点 */
    xmlFreeDoc(doc);
}

static void xml_parser(void)
{
    xmlDocPtr doc = xmlReadFile(XML_FILE_NAME, "UTF-8", XML_PARSE_RECOVER);
    xmlNodePtr curNode = NULL;
    xmlChar *tmpString = NULL;

    if (NULL == doc) {
        fprintf(stderr, "document not parsed successfully\n");
        exit(1);
    }

    curNode = xmlDocGetRootElement(doc);
    if (NULL == curNode) {
        fprintf(stderr, "empty document\n");
        xmlFreeDoc(doc);
        exit(1);
    }

    if (xmlStrcmp(curNode->name, BAD_CAST"\"root\"")) {
        fprintf(stderr, "document of the wrong type, root node != root\n");
        xmlFreeDoc(doc);
        exit(1);
    }

    curNode = curNode->children;
    xmlNodePtr propNodePtr = NULL;

    for (; curNode; curNode = curNode->next) {
        if (!xmlStrcmp(curNode->name, BAD_CAST"newNode1")) {
            tmpString = xmlNodeGetContent(curNode);
            printf("newNode1: %s\n", tmpString);
            xmlFree(tmpString);
        }

        if (xmlHasProp(curNode, BAD_CAST"attribute")) {
            propNodePtr = curNode;
        }
    }

    xmlAttrPtr attrPtr = propNodePtr->properties;
    for (; attrPtr; attrPtr = attrPtr->next ) {
        if (!xmlStrcmp(attrPtr->name, BAD_CAST"attribute")) {
            tmpString = xmlGetProp(propNodePtr, BAD_CAST"attribute");
            printf("get attribute: %s\n", tmpString);
            xmlFree(tmpString);
        }
    }

    xmlFreeDoc(doc);
}

int main(int argc, char *argv[])
{
    argc = argc;
    argv = argv;

    xml_save();
    xml_parser();

    return 0;
}
